/**
  ******************************************************************************
  * @file    tc32l010_pwr.c
  * @author  CHIPAT Application Team
  * @brief   This file provides firmware functions to manage the following
  *          functionalities of the Power Controller (PWR) peripheral:
  *           + Backup Domain Access
  *           + PVD configuration
  *           + WakeUp pins configuration
  *           + Low Power modes configuration
  *           + Flags management
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tc32l010_pwr.h"


/** @addtogroup tc32l010_StdPeriph_Driver
  * @{
  */

/** @defgroup PWR
  * @brief PWR driver modules
  * @{
  */
#define PWR_WPR_KEY1                          0x88
#define PWR_WPR_KEY2                          0x83

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


/**
  * @brief  Deinitializes the PWR peripheral registers to their default reset values.
  * @param  None
  * @retval None
  */
void PWR_DeInit(void)
{
    RCC_APBPeriphResetCmd(RCC_APBPeriph_PWR, ENABLE);
    RCC_APBPeriphResetCmd(RCC_APBPeriph_PWR, DISABLE);
}

/**
  * @brief  Enables or disables access to the PWR registers.
  * @param  NewState: new state of the access to the PWR registers.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void PWR_AccessCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the PWR register Access */
        PWR->WPR = PWR_WPR_KEY1;
        PWR->WPR = PWR_WPR_KEY2;
    }
    else
    {
        /* Disable the PWR register Access */
        PWR->WPR = 0x00;
        PWR->WPR = 0x00;
    }
}

/**
  * @}
  */
/**
  * @brief  set the sram retain mode.
  * @param  Sram_Mode: sram mode.
  *          This parameter can be one of the following values:
  *             @arg SRAM_RETAIN_MODE_0: mode 0
  *             @arg SRAM_RETAIN_MODE_1: mode 1
  * @retval None
  */
void PWR_SetSramRetainMode(uint8_t Sram_Mode)
{
    /* Check the parameters */
    assert_param(IS_SRAM_RETAIN_MODE(Sram_Mode));

    if (Sram_Mode == SRAM_RETAIN_MODE_0)
    {
        PWR->CR1 &= ~PWR_CR1_SRAM_RM;
    }
    else
    {
        PWR->CR1 |= PWR_CR1_SRAM_RM;
    }
}

/**
  * @brief  Enters Sleep mode.
  * @note   In Sleep mode, all I/O pins keep the same state as in Run mode.
  * @param  PWR_Mode: specifies if SLEEP mode in entered with WFI or WFE instruction.
  *          This parameter can be one of the following values:
  *             @arg PWR_SLEEPMODE_0: enter SLEEP mode with lvos normal instruction
  *             @arg PWR_SLEEPMODE_1: enter SLEEP mode with lvos step-down instruction
  *             @arg PWR_LPSLEEPMODE_0: enter SLEEP mode with LPR and lvos normal instruction
  *             @arg PWR_LPSLEEPMODE_1: enter SLEEP mode with LPR and lvos step-down instruction
  * @retval None
  */
void PWR_EnterSleepMode(uint32_t PWR_Mode)
{
    uint32_t reg;

    /* Check the parameters */
    assert_param(IS_PWR_SLEEPMODE(PWR_Mode));

    reg = PWR->CR1;

    reg &= ~(PWR_CR1_LPR | PWR_CR1_LVOS | PWR_CR1_MVOS);

    PWR->CR1 = reg | PWR_Mode;

    /* Clear SLEEPDEEP bit of Cortex-M0 System Control Register */
    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);

    /* Select SLEEP mode entry -------------------------------------------------*/
    /* Request Wait For Interrupt */
    __WFI();
}

/**
  * @brief  Enters STOP mode.
  * @note   In Stop mode, all I/O pins keep the same state as in Run mode.
  * @note   When exiting Stop mode by issuing an interrupt or a wakeup event,
  *         the HSI RC oscillator is selected as system clock.
  * @note   When the voltage regulator operates in low power mode, an additional
  *         startup delay is incurred when waking up from Stop mode.
  *         By keeping the internal regulator ON during Stop mode, the consumption
  *         is higher although the startup time is reduced.
  * @param  PWR_Mode: specifies the LSI state in STOP mode.
  *         This parameter can be one of the following values:
  *             @arg PWR_STOPMODE_0_LPVOS0: STOP mode with MLDO(1.2v) ON
  *             @arg PWR_STOPMODE_0_LPVOS1: STOP mode with MLDO(0.9v) ON
  *             @arg PWR_STOPMODE_1_LPVOS0: STOP mode with MLDO OFF,LSE\LSI ON, ULPLDO(1.2v) ON
  *             @arg PWR_STOPMODE_1_LPVOS1: STOP mode with MLDO OFF,LSE\LSI ON, ULPLDO(0.9v) ON
  *             @arg PWR_STOPMODE_2_LPVOS0: STOP mode with MLDO OFF,LSE\LSI OFF, ULPLDO(1.2v) ON
  *             @arg PWR_STOPMODE_2_LPVOS1: STOP mode with MLDO OFF,LSE\LSI OFF, ULPLDO(0.9v) ON
  * @param  PWR_STOPEntry: specifies if STOP mode in entered with WFI instruction.
  *         This parameter can be one of the following values:
  *             @arg PWR_STOPEntry_WFI: enter STOP mode with WFI instruction
                @arg PWR_STOPEntry_SLEEPONEXIT: enter STOP mode with SLEEPONEXIT instruction
  * @retval None
  */
void PWR_EnterSTOPMode(uint32_t PWR_Mode, uint8_t PWR_STOPEntry)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_PWR_STOPMODE(PWR_Mode));
    assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));

    /* Select the regulator state in STOP mode ---------------------------------*/
    tmpreg = PWR->CR1;
    /* Clear LPMS bits */
    tmpreg &= ~(PWR_CR1_LPMS | PWR_CR1_LPVOS | PWR_CR1_MVOS);

    /* Set LPMS bit according to PWR_CR1 value */
    tmpreg |= PWR_Mode | PWR_CR1_SRAM_RM | PWR_CR1_FLASH_DPD | PWR_CR1_VREF12_PD | PWR_CR1_FLASH_PORB;

    /* Store the new value */
    PWR->CR1 = tmpreg;

    /* Set SLEEPDEEP bit of Cortex-M0 System Control Register */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    /* Select STOP mode entry --------------------------------------------------*/
    if(PWR_STOPEntry == PWR_STOPEntry_WFI)
    {
        /* Request Wait For Interrupt */
        __WFI();
        /* Reset SLEEPDEEP bit of Cortex System Control Register */
        SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
    }
    else
    {
        /* Set SLEEP on exit bit of Cortex-M0 System Control Register */
        SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
    }
}

/**
  * @brief enter the run mode.
  * @param  PWR_Mode: the flag to check.
  *          This parameter can be one of the following values:
  *             @arg PWR_RUN_MODE0: mode 0(high clock@24MHz, MR@1.2v)
  *             @arg PWR_RUN_MODE1: mode 1(high clock@4MHz, MR@0.9v)
  *             @arg PWR_LPRUN_MODE0: lp mode 0(close high clock, low clock@32.768KHz open, ULPLDO@1.2v open)
  *             @arg PWR_LPRUN_MODE1: lp mode 1(close high clock, low clock@32.768KHz open, ULPLDO@0.9v open)
  * @retval The new state of PWR_FLAG (SET or RESET).
  */
void PWR_EnterRunMode(uint32_t PWR_Mode)
{
    uint32_t tempreg;

    /* Check the parameters */
    assert_param(IS_PWR_RUNMODE(PWR_Mode));

    tempreg = PWR->CR1;

    tempreg &= ~(PWR_CR1_LPR | PWR_CR1_LVOS | PWR_CR1_MVOS);

    PWR->CR1 = (tempreg | PWR_Mode);
}

 /**
  * @brief switch the ldo status.
  * @param  PWR_LDO: the flag to check.
  *          This parameter can be one of the following values:
  *             @arg PWR_LDO_MAST: master mode.
  *             @arg PWR_LDO_LOWPOWER: lowpower mode.
  * @retval None.
  */
void PWR_SwitchLDOStatus(uint16_t PWR_LDO)
{
    uint32_t tempreg;

    /* Check the parameters */
    assert_param(IS_PWR_LDO_STATUS(PWR_LDO));

    tempreg = PWR->CR1;

    tempreg &= ~PWR_CR1_LPR;

    PWR->CR1 = (tempreg | PWR_LDO);
}

/**
  * @}
  */


/**
  * @brief  Checks whether the specified PWR flag is set or not.
  * @param  PWR_FLAG: specifies the flag to check.
  *          This parameter can be one of the following values:
  *             @arg PWR_FLAG_LVD_INTF: LVD happen interrupt flag
  *             @arg PWR_FLAG_LVD_FILTER: filter flag
  * @retval The new state of PWR_FLAG (SET or RESET).
  */
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG)
{
    FlagStatus bitstatus = RESET;
    /* Check the parameters */
    assert_param(IS_PWR_GET_FLAG(PWR_FLAG));

    if ((PWR->LVD_SR & PWR_FLAG) != (uint32_t)RESET)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }
    /* Return the flag status */
    return bitstatus;
}

/**
  * @brief  Clears the PWR's pending flags.
  * @param  PWR_FLAG: specifies the flag to clear.
  *          This parameter can be one of the following values:
  *             @arg PWR_FLAG_LVD_INTF: LVD happen interrupt flag
  * @retval None
  */
void PWR_ClearFlag(uint32_t PWR_FLAG)
{
    /* Check the parameters */
    assert_param(IS_PWR_CLEAR_FLAG(PWR_FLAG));

    PWR->LVD_CR &=  ~PWR_FLAG;
}

/**
  * @brief  Adjusts the Triming calibration value.
  * @param  source: Voltage source.
  *          This parameter can be any combination of the following values:
  *             @arg PWR_MLDO_1V2: 
  *             @arg PWR_MLDO_0V9: 
  *             @arg PWR_ULPLDO_1V2: 
  *             @arg PWR_ULPLDO_0V9: 
  *             @arg PWR_VREF_1V2: 
  *             @arg PWR_VREF_0V7: 
  * @retval None
  */
void PWR_SET_LDOTrimValue(uint32_t source)
{
    __IO uint32_t TrimValue;
    __IO uint32_t tempreg1, tempreg2;

	RCC->PERIENR |= RCC_APBPeriph_PWR;
	PWR->WPR = PWR_WPR_KEY1;
	PWR->WPR = PWR_WPR_KEY2;

    switch (source)
    {
    case PWR_MLDO_1V2:
        tempreg1 = (*(__IO uint32_t *)(0x1FFFFC08));
        tempreg1 &= PWR_CR2_MLDO_H;

        tempreg2 = PWR->CR2;
        tempreg2 &= ~(PWR_CR2_MLDO_H);
        tempreg2 |= tempreg1;
        PWR->CR2 = tempreg2;
        break;

    case PWR_MLDO_0V9:
        tempreg1 = (*(__IO uint32_t *)(0x1FFFFC08));
        tempreg1 &= PWR_CR2_MLDO_L;

        tempreg2 = PWR->CR2;
        tempreg2 &= ~(PWR_CR2_MLDO_L);
        tempreg2 |= tempreg1;
        PWR->CR2 = tempreg2;
        break;

    case PWR_ULPLDO_1V2:
        tempreg1 = (*(__IO uint32_t *)(0x1FFFFC04));
        tempreg1 &= (0X0000001F);

        tempreg2 = PWR->CR2;
        tempreg2 &= ~(PWR_CR2_ULPLDO_H);
        tempreg2 |= (tempreg1 << 16);
        PWR->CR2 = tempreg2;
        break;

    case PWR_ULPLDO_0V9:
        tempreg1 = (*(__IO uint32_t *)(0x1FFFFC04));
        tempreg1 &= (0X0000001F << 8);

        tempreg2 = PWR->CR2;
        tempreg2 &= ~(PWR_CR2_ULPLDO_L);
        tempreg2 |= (tempreg1 << 16);
        PWR->CR2 = tempreg2;
        break;

    case PWR_VREF_1V2:
        tempreg1 = (*(__IO uint32_t *)(0x1FFFFC0C));
        tempreg1 &= PWR_CR3_VREF12;

        tempreg2 = PWR->CR3;
        tempreg2 &= ~(PWR_CR3_VREF12);
        tempreg2 |= tempreg1;
        PWR->CR3 = tempreg2;
        break;

    case PWR_VREF_0V7:
        tempreg1 = (*(__IO uint32_t *)(0x1FFFFC0C));
        tempreg1 &= PWR_CR3_MBGP;

        tempreg2 = PWR->CR3;
        tempreg2 &= ~(PWR_CR3_MBGP);
        tempreg2 |= tempreg1;
        PWR->CR3 = tempreg2;
        break;

    default:
        break;
    }
}

/**
  * @brief  Config the LVD.
  * @param  uLVD: pointer to a LVD_Config_U structure.
  * note   Must clear CTRLEN bit, and configurattion must be 
           delayed 400us by software.
  * @retval None
  */
void PWR_LVDConfig(LVD_Config_U uLVD)
{
  /* Check the parameters */
  assert_param(IS_LVD_VCC_SEL(uLVD.LVD_CR.VccSel));
  assert_param(IS_LVD_REF_SEL(uLVD.LVD_CR.RefSel));
  assert_param(IS_LVD_ACT_MODE(uLVD.LVD_CR.Act));
  assert_param(IS_LVD_FILTER_NUMBER(uLVD.LVD_CR.FltNum));

  /* must clear CTRLEN bit */
  PWR->LVD_CR = uLVD.Data & (~LVD_CR_CTRLEN);
}

/**
  * @brief  Enables or disables the LVD.      
  * @param  NewState: new state of the CTRLEN Bit.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void PWR_LVDCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    /* Set the CTRLEN bit */
    PWR->LVD_CR |= LVD_CR_CTRLEN;
  }
  else
  {
    /* Clear the CTRLEN bit */
    PWR->LVD_CR &= ~LVD_CR_CTRLEN;
  }
}

/**
  * @brief  Clear LVD Interrupt.
  * @param  None
  * @retval None
  */
void LVD_ClearITPendingBit(void)
{
    PWR->LVD_SR &= ~(LVD_SR_INTF);
}
/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT CHIPAT *****END OF FILE****/
